/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ar.edu.unicen.twitter.suggest.backend.recommendation.crawling.RecolectorDataset;

import ar.edu.unicen.twitter.suggest.backend.datasources.dao.TwitterDatasetDao;
import ar.edu.unicen.twitter.suggest.backend.datasources.dao.TwitterDatasetDaoImpl;
import ar.edu.unicen.twitter.suggest.backend.dtos.UsuarioDataset;
import ar.edu.unicen.twitter.suggest.backend.dtos.UsuarioDatasetAbstracto;
import ar.edu.unicen.twitter.suggest.backend.dtos.UsuarioDatasetProxy;
import ar.edu.unicen.twitter.suggest.backend.recommendation.CompararUsuarios.CompararUsuarios;
import ar.edu.unicen.twitter.suggest.backend.recommendation.CriterioUsuario.CriterioUsuario;
import ar.edu.unicen.twitter.suggest.backend.recommendation.crawling.NivelRecoleccion;
import ar.edu.unicen.twitter.suggest.backend.recommendation.crawling.RecoleccionFactory;
import ar.edu.unicen.twitter.suggest.backend.recommendation.crawling.Transicion.Transicion;
import ar.edu.unicen.twitter.suggest.backend.recommendation.crawling.Transicion.TransicionBinaria;
import ar.edu.unicen.twitter.suggest.backend.recommendation.crawling.Transicion.TransicionBinariaNormalizada;
import ar.edu.unicen.twitter.suggest.backend.recommendation.crawling.Transicion.TransicionProbabilisticaAmigos;
import ar.edu.unicen.twitter.suggest.backend.recommendation.crawling.Transicion.TransicionProbabilisticaSeguidores;
import ar.edu.unicen.twitter.suggest.backend.recommendation.crawling.Transicion.TransicionProbabilisticaSeguidos;
import ar.edu.unicen.twitter.suggest.commons.dtos.Usuario;
import ar.edu.unicen.twitter.suggest.commons.tools.CollectionsOperations;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Alex
 */
public class RecolecionDatasetFactory implements RecoleccionFactory {

    private final static Logger LOGGER = Logger.getLogger(RecolecionDatasetFactory.class.getName());
    TwitterDatasetDao twitterDatasetDao;
    private int maxArcos = 10000;

    public RecolecionDatasetFactory(TwitterDatasetDao twitterDatasetDao) {
        this.twitterDatasetDao = twitterDatasetDao;
    }

    @Override
    public NivelRecoleccion getNivelRecoleccion(TipoNivel tipoNivel, TipoTransicion tipoTransicion, CriterioUsuario criterio, CompararUsuarios comparador, int maxNivel) {
        Transicion transicion = null;
        if (tipoTransicion == TipoTransicion.Binaria) {
            transicion = new TransicionBinaria();
        } else if (tipoTransicion == TipoTransicion.Normalizada) {
            transicion = new TransicionBinariaNormalizada();
        }
        if (tipoNivel == TipoNivel.NivelSeguidores) {
            if (tipoTransicion == TipoTransicion.Probabilistica) {
                transicion = new TransicionProbabilisticaSeguidores();

            }
            if (transicion != null) {
                return new NivelSeguidoresDataset(this, criterio, comparador, transicion, maxNivel);
            }
        } else if (tipoNivel == TipoNivel.NivelSeguidos) {
            if (tipoTransicion == TipoTransicion.Probabilistica) {
                transicion = new TransicionProbabilisticaSeguidos();

            }
            if (transicion != null) {
                return new NivelSeguidosDataset(this, criterio, comparador, transicion, maxNivel);
            }
        } else if (tipoNivel == TipoNivel.NivelAmigos) {
            if (tipoTransicion == TipoTransicion.Probabilistica) {
                transicion = new TransicionProbabilisticaAmigos();
            }
            if (transicion != null) {
                return new NivelAmigosDataset(this, criterio, comparador, transicion, maxNivel);
            }
        }
        return null;
    }

    @Override
    public Usuario getUsuario(long id) {
        return twitterDatasetDao.getUsuarioLazy((int) id);
    }

    private int[] reducir(int[] usuarios) {
        // LOGGER.log(Level.INFO, "Reduciendo {0}", usuarios.length);
        int[] resultado;
        if (maxArcos <= 0 || usuarios.length <= maxArcos) {
            resultado = usuarios;
        } else {
            int step = usuarios.length / maxArcos;
            resultado = new int[maxArcos];
            for (int i = 0; i < maxArcos; i++) {
                resultado[i] = usuarios[i * step];
            }
        }
        //LOGGER.log(Level.INFO, "reducido a {0}", resultado.length);
        return resultado;
    }

    @Override
    public Collection<Usuario> getSeguidos(Usuario u) {
        int[] ids = ((UsuarioDatasetAbstracto) u).getFollowsShortIds();
        return twitterDatasetDao.getUsuariosLazy(CollectionsOperations.getList(reducir(ids)));
    }

    @Override
    public Collection<Usuario> getSeguidores(Usuario u) {
        int[] ids = ((UsuarioDatasetAbstracto) u).getFollowersShortIds();
        return twitterDatasetDao.getUsuariosLazy(CollectionsOperations.getList(reducir((ids))));
    }

    @Override
    public Collection<Usuario> getAmigos(Usuario u) {
        int[] idsSeguidores = ((UsuarioDatasetAbstracto) u).getFollowersShortIds();
        int[] idsSeguidos = ((UsuarioDatasetAbstracto) u).getFollowsShortIds();
        return twitterDatasetDao.getUsuariosLazy(CollectionsOperations.getListIntersection(reducir(idsSeguidores), reducir(idsSeguidos)));
    }

    @Override
    public Collection<Usuario> verificar(Collection<Usuario> usuarios) {
        List<Long> ids = new ArrayList<Long>();
        Map<Long, Integer> indice = new HashMap<Long, Integer>();
        int i = 0;
        for (Usuario usuario : usuarios) {
            if (!((UsuarioDatasetProxy) usuario).isInitialized()) {
                ids.add(usuario.getId());
                indice.put(usuario.getId(), i);
                i++;
            }
        }
        List<UsuarioDataset> verificados = (List<UsuarioDataset>) twitterDatasetDao.getUsuariosSmall(ids);
        for (Usuario usuario : usuarios) {
            if (!((UsuarioDatasetProxy) usuario).isInitialized()) {
                ((UsuarioDatasetProxy) usuario).setUsuarioSmall(verificados.get(indice.get(usuario.getId())));
            }
        }
        return usuarios;

    }

    public int getMaxArcos() {
        return maxArcos;
    }

    public void setMaxArcos(int maxArcos) {
        this.maxArcos = maxArcos;
    }
}
